/*
 *  Copyright (C) 2010 glauco
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.balisunrise.bindings.swing;

import javax.swing.JComponent;
import org.balisunrise.bindings.BeansBinding;
import org.balisunrise.bindings.BeansBindingSupport;
import org.balisunrise.bindings.BindingPropertyListener;
import org.balisunrise.bindings.BindingSupport;
import org.balisunrise.bindings.DefaultBindingGroup;
import org.balisunrise.common.Basic;
import org.balisunrise.common.BindingGroup;
import org.balisunrise.common.ComponentManager;
import org.balisunrise.common.FieldInput;

/**
 * Factory de Bindings e BindingGroup.
 *
 * @author Glauco
 */
public class BindingBuilder implements 
        org.balisunrise.builder.BindingBuilder<BeansBinding>{

    /**
     * Cria grupo de Binding {@link org.balisunrise.common.BindingGroup}
     *
     * @return nova instância de BindingGroup.
     */
    @Override
    public BindingGroup createBindingGroup() {
        return new DefaultBindingGroup();
    }

    /**
     * Cria um novo Binding a partir de um Source e um Target e suas
     * propriedades que devem ser vinculadas.
     *
     * @param bindingGroup Grupo de Binding que receberá o Binding criado.
     * @param source Objeto Source.
     * @param sourceProperty Nome da Propriedade de Source.
     * @param target Objeto Target.
     * @param targetProperty Nome da Propriedade de Target.
     * @return A instância do Binding criado e adicionado ao BindingGroup.
     */
    @Override
    public BeansBinding createBinding(BindingGroup bindingGroup,
            Object source, String sourceProperty,
            Object target, String targetProperty) {

        return createBinding(bindingGroup, source,
                sourceProperty, target, targetProperty, null, false);
    }

    /**
     * Cria um novo Binding a partir de um Source e um Target e suas
     * propriedades que devem ser vinculadas, e um ComponentManager para
     * ler e escrever os dados no Target.
     * Este tipo de Binding assume que o Target é um componente de representação
     * visual.
     *
     * @param bindingGroup Grupo de Binding que receberá o Binding criado.
     * @param source Objeto Source.
     * @param sourceProperty Nome da Propriedade de Source.
     * @param target Objeto Target.
     * @param targetProperty Nome da Propriedade de Target.
     * @param componentManager Controle para leitura e escrita dos dados do
     * Target.
     * @param nullForEmpty Instrução de leitura do ComponentManager.
     * @return A instância do Binding criado e adicionado ao BindingGroup.
     */
    @Override
    public BeansBinding createBinding(BindingGroup bindingGroup,
            Object source, String sourceProperty,
            Object target, String targetProperty,
            ComponentManager componentManager,
            boolean nullForEmpty) {

        return createBinding(bindingGroup, source, sourceProperty,
                target, targetProperty, componentManager, nullForEmpty, null);
    }

    /**
     * Cria um novo Binding a partir de um Source e um Target e suas
     * propriedades que devem ser vinculadas, e um ComponentManager para
     * ler e escrever os dados no Target.
     * Este tipo de Binding assume que o Target é um componente de representação
     * visual, e que existe um Basic owner do componente visual.
     *
     *
     * @param bindingGroup Grupo de Binding que receberá o Binding criado.
     * @param source Objeto Source.
     * @param sourceProperty Nome da Propriedade de Source.
     * @param target Objeto Target.
     * @param targetProperty Nome da Propriedade de Target.
     * @param componentManager Controle para leitura e escrita dos dados do
     * Target.
     * @param nullForEmpty Instrução de leitura do ComponentManager.
     * @param owner Basic proprietário da representação visual (Target).
     * @return  A instância do Binding criado e adicionado ao BindingGroup.
     */
    @Override
    public BeansBinding createBinding(BindingGroup bindingGroup, Object source,
            String sourceProperty, Object target, String targetProperty,
            ComponentManager componentManager, boolean nullForEmpty,
            Basic owner) {

        BeansBinding binding = create(source, sourceProperty, target,
                targetProperty, componentManager, nullForEmpty, owner);

        if(binding == null)
            return null;
        
        bindingGroup.addBinding(binding);

        return binding;
    }

    /**
     *
     * @param source
     * @param sourceProperty
     * @param target
     * @param targetProperty
     * @param componentManager
     * @param nullForEmpty
     * @return
     */
    public BeansBinding create(Object source, String sourceProperty,
            Object target, String targetProperty,
            ComponentManager componentManager, boolean nullForEmpty,
            Basic owner){


        BeansBindingSupport sourceSupport =
                new BeansBindingSupport(source, sourceProperty);

        BindingSupport targetSupport;


        if (target instanceof JComponent && componentManager != null)
            targetSupport = new SwingSupport(target, componentManager);
        else
            targetSupport = new BeansBindingSupport(target, targetProperty);
        
        BeansBinding binding = new BeansBinding(source, target,
                sourceProperty, targetProperty, sourceSupport, targetSupport);

        if (owner != null && owner instanceof FieldInput){
            FieldInput fi = (FieldInput) owner;
            SwingComponentTrigger targetTrigger = new SwingComponentTrigger(
                    fi, binding, BindingPropertyListener.TARGET);
            binding.setTargetTrigger(targetTrigger);
        }

        if(componentManager != null){
            binding.setConverter(componentManager.getConverter(nullForEmpty));
        }

        return binding;
    }
}
